package com.xinggq.auth.service.service.impl;

import com.xinggq.auth.api.dto.login.AuthSafeUserInfoDTO;
import com.xinggq.auth.api.dto.login.LoginRequest;
import com.xinggq.auth.api.dto.login.LoginResponse;
import com.xinggq.auth.api.dto.login.TokenInfoDTO;
import com.xinggq.auth.api.dto.token.RefreshTokenRequest;
import com.xinggq.auth.api.exception.AuthException;
import com.xinggq.auth.service.config.AuthProperties;
import com.xinggq.auth.service.feign.UserCenterFeignClient;
import com.xinggq.auth.service.service.LoginManagerService;
import com.xinggq.auth.service.service.TokenManagerService;
import com.xinggq.common.CommonResult;
import com.xinggq.common.utils.Validate;
import com.xinggq.user.api.dto.UserInfoDTO;
import com.xinggq.user.api.dto.VerifyPasswordRequest;
import com.xinggq.user.api.dto.VerifyPasswordResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

/**
 * 认证服务实现类
 * 提供用户登录、令牌刷新和登出功能
 * 采用双token认证方案：访问令牌(access token)和刷新令牌(refresh token)
 *
 * @author xinggq
 * @since 2024-01-01
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class LoginManagerServiceImpl implements LoginManagerService {

  private final TokenManagerService tokenManager;
  private final AuthProperties authProperties;
  private final UserCenterFeignClient userCenterFeignClient;

  @Override
  public LoginResponse login(LoginRequest loginRequest) {
    log.info("用户登录请求: {}", loginRequest.getUsername());
    // 参数校验
    Validate.strNotBlank(loginRequest.getUsername(), "用户名不能为空");
    Validate.strNotBlank(loginRequest.getPassword(), "密码不能为空");
    try {
      // 调用用户中心验证密码
      VerifyPasswordRequest verifyRequest = new VerifyPasswordRequest();
      verifyRequest.setUsername(loginRequest.getUsername());
      verifyRequest.setPassword(loginRequest.getPassword());

      CommonResult<VerifyPasswordResponse> commonResult = userCenterFeignClient.verifyPassword(
          verifyRequest);

      if (!commonResult.isSuccess() || !commonResult.getData().isSuccess()) {
        String failReason = commonResult.getData() == null ? commonResult.getMsg() : commonResult.getData().getFailReason();
        log.warn("用户密码验证失败: {}", failReason);
        throw AuthException.invalidCredentials(failReason);
      }

      // 获取用户信息
      UserInfoDTO userInfo = commonResult.getData().getUserInfo();

      // 生成双令牌
      boolean rememberMe = loginRequest.getRememberMe() != null && loginRequest.getRememberMe();
      String accessToken = tokenManager.generateAccessToken(userInfo, rememberMe);
      String refreshToken = tokenManager.generateRefreshToken(userInfo);
      
      // 处理用户会话管理
      boolean allowLogin = tokenManager.handleUserSession(userInfo.getId(), accessToken);
      if (!allowLogin) {
        log.warn("用户 {} 登录被拒绝，已有活跃会话", userInfo.getUsername());
        throw AuthException.sessionConflict("用户已在其他设备登录，请先退出后再登录");
      }
      int activeSessionCount = tokenManager.getActiveSessionCount(userInfo.getId());
      log.info("用户 {} 登录成功，当前用户活跃的会话数量: {}", userInfo.getUsername(), activeSessionCount);

      TokenInfoDTO tokenInfo = TokenInfoDTO.builder()
          .accessToken(accessToken)
          .refreshToken(refreshToken)
          .tokenType("Bearer")
          .expiresIn(authProperties.getTokenValiditySeconds())
          .build();
      AuthSafeUserInfoDTO authSafeUserInfo = AuthSafeUserInfoDTO.builder()
          .userId(userInfo.getId())
          .username(userInfo.getUsername())
          .tenantId(userInfo.getTenantId())
          .lastLoginTime(userInfo.getLastLoginTime())
          .build();

      // 构建并返回登录响应
      return LoginResponse.builder().tokenInfo(tokenInfo).userInfo(authSafeUserInfo).build();
    } catch (AuthException e) {
      throw e;
    } catch (Exception e) {
      log.error("用户登录失败: {}", e.getMessage(), e);
      throw AuthException.invalidCredentials("用户名或密码错误");
    }
  }

  @Override
  public void logout(String token) {
    log.info("用户登出请求");
    // 参数校验
    Validate.strNotBlank(token, "令牌不能为空");
    try {
      // 撤销令牌
      tokenManager.revokeToken(token);
      log.info("用户登出成功");
    } catch (Exception e) {
      log.error("用户登出失败: {}", e.getMessage(), e);
      throw AuthException.operationFailed("登出失败");
    }
  }

  @Override
  public LoginResponse refreshToken(RefreshTokenRequest refreshTokenRequest) {
    log.info("刷新令牌请求");
    // 参数校验
    Validate.strNotBlank(refreshTokenRequest.getRefreshToken(), "刷新令牌不能为空");

    try {
      // 验证刷新令牌并获取用户ID
      Long userId = tokenManager.validateRefreshToken(refreshTokenRequest.getRefreshToken());

      // 根据用户ID获取用户信息
      CommonResult<UserInfoDTO> commonResult = userCenterFeignClient.getUserById(userId);
      if (!commonResult.isSuccess() || commonResult.getData() == null) {
        log.warn("用户不存在，用户ID: {}", userId);
        throw AuthException.invalidToken("用户不存在");
      }

      // 撤销旧刷新令牌
      tokenManager.revokeRefreshToken(refreshTokenRequest.getRefreshToken());
      UserInfoDTO userInfo = commonResult.getData();
      // 生成新的双令牌
      String newAccessToken = tokenManager.generateAccessToken(userInfo, false);
      String newRefreshToken = tokenManager.generateRefreshToken(userInfo);

      TokenInfoDTO tokenInfo = TokenInfoDTO.builder()
          .accessToken(newAccessToken)
          .refreshToken(newRefreshToken)
          .tokenType("Bearer")
          .expiresIn(authProperties.getTokenValiditySeconds())
          .build();

      AuthSafeUserInfoDTO authSafeUserInfo = AuthSafeUserInfoDTO.builder()
          .userId(userInfo.getId())
          .username(userInfo.getUsername())
          .tenantId(userInfo.getTenantId())
          .lastLoginTime(userInfo.getLastLoginTime())
          .build();

      log.info("刷新令牌成功，用户ID: {}", userId);
      return LoginResponse.builder()
          .tokenInfo(tokenInfo)
          .userInfo(authSafeUserInfo)
          .build();

    } catch (AuthException e) {
      throw e;
    } catch (Exception e) {
      log.error("刷新令牌失败: {}", e.getMessage(), e);
      throw AuthException.invalidToken("刷新令牌失败");
    }
  }

}